from sqlite3 import dbapi2 as sqlite
from path import path as Path

from wcs.libs.database.base import SQLBase
from wcs.libs.database.parser import SQLFileParser

__all__ = ["SQLiteManager"]

class SQLiteManager(SQLBase):
    """
    A class to manager the database transactions. This will contain functions 
    for us to manager and create the database itself so we don't have to 
    concentrate on SQLite commands.
    """
    def __init__(self, pathFile):
        """
        Default constructor. Store the paths and build the table structure of 
        the database.
        
        @param str|path.path pathFile The path to the database file
        """
        if isinstance(pathFile, Path):
            self.pathFile = pathFile
        else:
            self.pathFile = Path(pathFile)
        
        """ 
        Parse the given sql file. This allows us to change how the database acts
        without rewriting the python source code
        """
        self.parseFile = self.pathFile.splitpath()[0].joinpath("install.sql")
        self.parser    = SQLFileParser(self.parseFile)
        self.parser.read()
        
        """ Open a database connection """
        self.connection = sqlite.connect(str(self.pathFile))
        self.cursor     = self.connection.cursor()

        """
        Ensure that we use basic string conversion instead of UTF8 so it
        doesn't error on unicode characters, it just simply ignores them.
        """
        self.connection.text_factory = str
        
        """ Iterate through the results and execute the stataments """
        for statement in self.parser:
            self.cursor.execute(statement)

    def execute(self, statement, *args):
        """
        Create a wraper to execute a command upon the SQL cursor.

        @param str statement The statement to execute on the cursor; any valid
                             SQL command.
        @param mixed args Optional unknown amount of elements to insert into the
                          execute query.
        """
        self.cursor.execute(statement, args)

    def fetchone(self):
        """
        Mimics the sqlite fetchone method which recides within a cursor object.
        Ensures that a single value is returned from the cursor object if only
        one object exists within the tuple from the query, otherwise it returns
        the query result

        @return mixed The result from the query command
        """
        objectResult = self.cursor.fetchone()
        if hasattr(objectResult, "__iter__"):
            if len(objectResult) == 1:
                return objectResult[0]
        return objectResult

    def fetchall(self):
        """
        Mimics the sqlite fetchall method which recides within a cursor object.
        Ensures that the true values are added to a list so that we don't need
        to index it if the value is only one item in length (e.g. item instead
        of (item,)...)

        @return list Attributes from which the query returned
        """
        trueValues = []
        for value in self.cursor.fetchall():
            if hasattr(value, "__iter__"):
                if len(value) > 1:
                    trueValues.append(value)
                else:
                    trueValues.append(value[0])
            else:
                trueValues.append(value)
        return trueValues

    def save(self):
        """
        Commits the database to harddrive so that we can load it if the server
        closes.

        @return bool Whether or not the database was saved
        """
        if str(self.pathFile) != ":memory:":
            self.connection.commit()
            return True
        return False


    def clear(self, saveDatabase = True):
        """
        Deletes all instance within the tables of the databse.

        @param bool saveDatabase Optional value, if True, it will commit the
                                 database
        """
        self.cursor.execute("DELETE FROM player")
        self.cursor.execute("DELETE FROM race")
        self.cursor.execute("DELETE FROM skill")
        if saveDatabase:
            self.save()

    def close(self):
        """
        Closes the connections so that no further queries can be made.
        """
        self.cursor.close()
        self.connection.close()